#ifndef ENGINE_SCENEMANAGER_H
#define ENGINE_SCENEMANAGER_H

#include <string>
#include <memory>
#include <unordered_map>
#include <functional>
#include <stdexcept> // For std::runtime_error
#include "Scene.h"   // Include Scene definition

namespace GameEngine {

class SceneManager {
public:
    SceneManager();
    ~SceneManager();

    // Register scene types through factory functions.
    template<typename T>
    void RegisterScene(const std::string& name) {
        static_assert(std::is_base_of<Scene, T>::value, "T must be derived from Scene");
        if (m_sceneFactories.find(name) != m_sceneFactories.end()) {
            return; // Already registered
        }
        // The following lambda expression is a "factory function".
        // When called, it creates a std::shared_ptr<T> instance.
        m_sceneFactories[name] = [this, name]() {
            auto scene = std::make_shared<T>(name);
            static_cast<Scene*>(scene.get())->m_sceneManager = this; // Pass manager pointer
            return scene;
        };
    }

    // Switch to the scene with the given name.
    // If the scene is not loaded, it will be created and initialized.
    void SwitchToScene(const std::string& name);

    // Update the current active scene.
    void UpdateCurrentScene(float deltaTime);

    // Render the current active scene.
    void RenderCurrentScene();

    // Get the current active scene.
    std::shared_ptr<Scene> GetCurrentScene() const;

    // Get a specific scene by name (create if it doesn't exist and is registered)
    std::shared_ptr<Scene> GetScene(const std::string& name);

    // Unload a specific scene by name
    void UnloadScene(const std::string& name);

    // Unload all scenes
    void UnloadAllScenes();

private:
    // m_sceneFactories stores the mapping from scene names to their corresponding "factory functions".
    std::unordered_map<std::string, std::function<std::shared_ptr<Scene>()>> m_sceneFactories;
    std::unordered_map<std::string, std::shared_ptr<Scene>> m_loadedScenes;
    std::shared_ptr<Scene> m_currentScene;
    std::string m_currentSceneName;
};

}

#endif
